package com.xunk.equipment.service.acrel.service;

import com.alibaba.fastjson.JSONObject;
import com.xunk.common.core.constant.CacheConstants;
import com.xunk.common.core.constant.HttpStatus;
import com.xunk.common.core.constant.MessageNotifyConstants;
import com.xunk.common.core.exception.CustomException;
import com.xunk.common.core.utils.DateUtils;
import com.xunk.common.core.utils.StringUtils;
import com.xunk.common.redis.service.RedisService;
import com.xunk.equipment.api.domain.MessageNotificationDO;
import com.xunk.equipment.config.MQTTClient;
import com.xunk.equipment.domain.AlarmParamDO;
import com.xunk.equipment.domain.EquipmentDO;
import com.xunk.equipment.mapper.EquipmentMapper;
import com.xunk.equipment.service.BaseService;
import com.xunk.equipment.service.acrel.vo.AcrelWaterControlReqVO;
import com.xunk.equipment.websocket.WebsocketManager;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * @ProjectName: xunk
 * @Package: com.xunk.equipment.service.acrel.service
 * @ClassName: PublishMessageComponent
 * @Author: dongxiaoxin
 * @Description: 想mqtt发现消息组件
 * @Date: 2021/4/12 18:42
 * @Version: 1.0
 */
@Component
@RefreshScope
public class PublishMessageComponent {

    @Resource
    @Qualifier("MQTT_83")
    MQTTClient client;

    @Value("#{'${equipment.fake:0}'.split(',')}")
    protected List<String> switchKey;

    @Autowired
    protected EquipmentMapper equipmentMapper;

    @Autowired
    protected RedisService service;

    @Autowired
    protected BaseService baseService;

    private final List<String> functions = Arrays.asList("watercontrol-heatcontrol".split("-").clone());

    protected Long publishMessage(EquipmentDO equipmentDO, boolean status, String functionId) {


        if (!functions.contains(functionId)){
            throw new CustomException("无效的控制指令");
        }

        MqttMessage message = new MqttMessage();

        String deviceSn = equipmentDO.getDeviceSn();
        checkAcrelGateStatus(deviceSn.split(":")[0]);

        Long homeId = equipmentMapper.selectHomeIdByDeviceSn(deviceSn);
        AcrelWaterControlReqVO vo = new AcrelWaterControlReqVO();
        String cUuid = System.currentTimeMillis() + String.format("%04d", new Random().nextInt(9999));
        Map<String, Object> map = new HashMap<>();
        map.put("id", homeId);
        map.put("status", status);
        map.put("deviceSn", deviceSn);
        service.setCacheObject(CacheConstants.ACREL_CONTROL_UUID + cUuid, map,1, TimeUnit.MINUTES);
        vo.setSaleId("10100001");
        //  网关id 此次先跟家庭绑定，后期根据对接情况再定
        vo.setGateId(deviceSn.split(":")[0]);
        vo.setCuuid(cUuid);
        vo.setMeterId(deviceSn.split(":")[1]);
        vo.setName(equipmentDO.getDeviceName());
        vo.setFunctionId(functionId);
        vo.setValue(status ? 1 : 0);
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        vo.setTime(df.format(new Date()));

        System.out.println(JSONObject.toJSONString(vo));
        message.setPayload(JSONObject.toJSONString(vo).getBytes(StandardCharsets.UTF_8));
        client.publish("v1/smartec/flowmeter/control", message);
        return homeId;
    }

    /**
     *  保存机电设备报警信息
     * @param deviceSn  设备sn号
     * @param content   告警内容
     * @param title   告警标题
     */
    public void saveAlarmInfo(String deviceSn,String content,String title){

        List<AlarmParamDO> list = equipmentMapper.selectAlarmInfo(deviceSn);
        List<MessageNotificationDO> messageList = new ArrayList<>();
        list.forEach(alarmParamDO -> {
            MessageNotificationDO message = new MessageNotificationDO();
            message.setContent(String.format(content,alarmParamDO.getHomeName(),alarmParamDO.getDeviceName()));
            message.setTitle(title);
            message.setType(MessageNotifyConstants.SYSTEM_TYPE);
            message.setUserId(alarmParamDO.getUserId());
            message.setDeptId(alarmParamDO.getDeptId());
            message.setTriggerId(deviceSn);
            message.setCreateTime(new Date());
            messageList.add(message);
        });
        baseService.insertMessageNotifications(messageList);
    }

    protected Boolean virtualDevice(String deviceSn, String value, String cacheKey){

        Long homeId = equipmentMapper.selectHomeIdByDeviceSn(deviceSn);
        service.setCacheObject(cacheKey + homeId,Boolean.parseBoolean(value));

        CompletableFuture.runAsync(() ->{
            Map<String,Object> dataMap = new HashMap<>();
            dataMap.put("on",value);

            Map<String,Object> map = new HashMap<>();
            map.put("deviceSn",deviceSn);
            EquipmentDO equipment = equipmentMapper.getEquipment(deviceSn);
            map.put("deviceType",equipment.getDeviceType());
            map.put("properties",dataMap);

            Map<String,Object> socketMessage = new HashMap<>();
            socketMessage.put("code", HttpStatus.SUCCESS);
            socketMessage.put("msg", "设备执行成功");
            socketMessage.put("type", 3);

            socketMessage.put("data", map);
            List<Long> users = equipmentMapper.selectUsersByDeviceSn(deviceSn);
            users.forEach(user -> WebsocketManager.appointSending(String.valueOf(user),JSONObject.toJSONString(socketMessage)));
        });
        return true;
    }

    private void checkAcrelGateStatus(String gateId) {

        String dateStr = service.getCacheObject(CacheConstants.ACREL_HEARTBEAT_TIME + gateId);
        if (StringUtils.isNotEmpty(dateStr) && DateUtils.addMinutes(DateUtils.parseDate(dateStr), 10).getTime() < new Date().getTime()) {
            throw new CustomException("网关设备已离线，无法发送控制指令");
        }
    }
}
